package net.intellect.collectpro.gestores;


import java.rmi.RemoteException;
import java.util.List;
import java.util.Map;

import net.intellect.collectpro.objects.Cartera;
import net.intellect.collectpro.objects.Empresa;
import net.intellect.collectpro.objects.EquipoGestores;
import net.intellect.collectpro.objects.Mora;
import net.intellect.collectpro.objects.Producto;
import net.intellect.force.ClientSalesforce;
import net.intellect.force.UtilBasic;

import org.apache.log4j.Logger;

import com.sforce.soap.enterprise.DeleteResult;
import com.sforce.soap.enterprise.ID;
import com.sforce.soap.enterprise.InvalidFieldFault;
import com.sforce.soap.enterprise.InvalidIdFault;
import com.sforce.soap.enterprise.InvalidQueryLocatorFault;
import com.sforce.soap.enterprise.InvalidSObjectFault;
import com.sforce.soap.enterprise.LoginFault;
import com.sforce.soap.enterprise.MalformedQueryFault;
import com.sforce.soap.enterprise.SaveResult;
import com.sforce.soap.enterprise.UnexpectedErrorFault;
import com.sforce.soap.enterprise.sobject.Conf_Cartera__c;
import com.sforce.soap.enterprise.sobject.Conf_Empresa__c;
import com.sforce.soap.enterprise.sobject.Conf_Equipo_Agentes_Det__c;
import com.sforce.soap.enterprise.sobject.Conf_Info_Mora__c;
import com.sforce.soap.enterprise.sobject.Conf_Info_Producto__c;
import com.sforce.soap.enterprise.sobject.SObject;

/**
 * Clase base para los gestores de salesforce
 * @author Gina
 *
 */
public class GestorSalesforce {
		
	
	protected static Logger logger = Logger.getLogger("salesforce");
	protected static final int MAX_INTENTOS = 100;
	protected static final String NULL = "NULL";
	
	protected String user = null;
	protected String password = null;
	protected String token = null;
	protected String host = null;	
	protected String codEmpresa = null;
	protected boolean isSandBox = false;
	protected String urlProxy = null;
	protected String puertoProxy = null;
	
	protected ClientSalesforce client;
	
	public GestorSalesforce(String user,String password,String token,String codEmpresa,boolean isSandBox,String urlProxy,String puertoProxy) {
		this.host = ClientSalesforce.HOST_PRODUCTION;		
		this.user = user;
		this.password = password;
		this.token = token;
		this.codEmpresa = codEmpresa;
		this.isSandBox = isSandBox;
		this.urlProxy = urlProxy;
		this.puertoProxy = puertoProxy;		
		if (isSandBox) {
			client = new ClientSalesforce(true,user,password,token,urlProxy,puertoProxy);
		} else {
			client = new ClientSalesforce(user,password,token,urlProxy,puertoProxy);
		}
	}		


	/*****************************************************************************************/
	/******************************FUNCIONES GENERALES****************************************/
	/*****************************************************************************************/
	/*****************************************************************************************/	
	
	/**
	 * Inserta una lista de registros
	 * @param registros
	 * @return
	 * @throws Exception
	 */
	
	protected boolean createRegistros(List<? extends SObject> registros) throws Exception{
		return createRegistros(registros,200);
	}		
	
	protected boolean createRegistros(List<? extends SObject> registros,int batchSize) throws UnexpectedErrorFault, Exception {
		boolean ok = false;
		if (registros==null || registros.size()==0) return true;		
		try {		
			SaveResult[] resultados = client.create(UtilBasic.convertirArraySObject(registros),batchSize);
			for (SaveResult resultado:resultados) {
				if (!resultado.getSuccess()) {
					logger.error("Error insertando el registro id " + resultado.getId());
					for (com.sforce.soap.enterprise.Error error:resultado.getErrors()) {
						logger.error("	" + error.getMessage());
					}
				}					
			}			
		} catch (Exception e) {
			logger.error(e);
		}
		return ok;	
	}	
	
	
	protected boolean deleteRegistros(List<ID> registros) throws Exception{
		boolean ok = false;
		if (registros==null || registros.size()==0) return true;		
		try {		
			ID[] ids = new ID[registros.size()];				
			DeleteResult[] resultados = client.delete(registros.toArray(ids));
			for (DeleteResult resultado:resultados) {
				if (!resultado.getSuccess()) {
					logger.error("Error eliminando el registro id " + resultado.getId());
					for (com.sforce.soap.enterprise.Error error:resultado.getErrors()) {
						logger.error("	" + error.getMessage());
					}
				}					
			}				
						
		} catch (Exception e) {
			logger.error(e);
		}
		return ok;	
	}		
	
	/**
	 * Actualiza e inserta una lista de SObject, sin procesar los errores
	 * @param registros
	 * @return
	 * @throws Exception
	 */
	protected boolean upsertRegistros(List<? extends SObject> registros) throws Exception{
		if (registros==null || registros.size()==0) return true;
		
		int numIntentos=0;
		boolean ok = false;
		while (numIntentos<MAX_INTENTOS) {
			try {						
				SaveResult[] resultados = client.upsert(UtilBasic.convertirArraySObject(registros));
				for (SaveResult resultado:resultados) {
					if (!resultado.getSuccess()) {
						logger.error("Error upsert el registro id " + resultado.getId());
						for (com.sforce.soap.enterprise.Error error:resultado.getErrors()) {
							logger.error("	" + error.getMessage());
						}
					}					
				}				
				ok = true;
				numIntentos = MAX_INTENTOS;
			} catch (Exception e) {
				logger.error(e);
				numIntentos++;
				if (numIntentos>=MAX_INTENTOS) {
					throw e;
				}
			}							
		}			
		return ok;	
	}
	
	
	
	/**
	 * Actualiza una lista de SObject, sin procesar los errores
	 * @param registros
	 * @return
	 * @throws Exception
	 */	
	protected boolean actualizarRegistros(List<? extends SObject> registros) throws Exception{
		return actualizarRegistros(registros,200);
	}
	
	
	/**
	 * Actualiza una lista de SObject, sin procesar los errores
	 * @param registros
	 * @return
	 * @throws Exception
	 */	
	protected boolean actualizarRegistros(List<? extends SObject> registros,int batchSize) throws Exception{
		if (registros==null || registros.size()==0) return true;
		
		int numIntentos=0;
		boolean ok = false;
		while (numIntentos<MAX_INTENTOS) {
			try {				
				SaveResult[] resultados = client.update(UtilBasic.convertirArraySObject(registros),batchSize);
				for (SaveResult resultado:resultados) {
					if (!resultado.getSuccess()) {
						logger.error("Error actualizando el registro id " + resultado.getId());
						for (com.sforce.soap.enterprise.Error error:resultado.getErrors()) {
							logger.error("	" + error.getMessage());
						}
					}					
				}
				ok = true;
				numIntentos = MAX_INTENTOS;
			} catch (Exception e) {
				logger.error(e);
				numIntentos++;
				if (numIntentos>=MAX_INTENTOS) {
					throw e;
				}
			}							
		}			
		return ok;	
	}	


	public List<SObject> getObjectsSalesforce(String strSOQLStmt,Integer queryBatchSize) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		int numIntentos=0;		
		while (numIntentos++<MAX_INTENTOS) {
			try {
				return client.getObjectsSalesforce(strSOQLStmt, queryBatchSize);				
			} catch (LoginFault e) {
				logger.error(e);
				throw e;							
			} catch (InvalidSObjectFault e) {
				logger.error(e);
				throw e;			
			} catch (MalformedQueryFault e) {
				logger.error(e);
				throw e;			
			} catch (InvalidIdFault e) {
				logger.error(e);
				throw e;
			} catch (InvalidFieldFault e) {
				logger.error(e);
				throw e;				
			} catch (UnexpectedErrorFault e) {
				logger.error(e);			
			} catch (InvalidQueryLocatorFault e) {
				logger.error(e);
			} catch (RemoteException e) {
				logger.error(e);		
			} catch (Exception e) {
				logger.error(e);	
			}
		}
		return null;
	}

	public List<SObject> getObjectsSalesforce(String strSOQLStmt) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		return this.getObjectsSalesforce(strSOQLStmt, null);
	}	
	
		
   	public SObject getObjectSalesforce(String strSOQLStmt) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		int numIntentos=0;		
		while (numIntentos++<MAX_INTENTOS) {
			try {
				return client.getObjectSalesforce(strSOQLStmt);				
			} catch (LoginFault e) {
				logger.error(e);
				throw e;							
			} catch (InvalidSObjectFault e) {
				logger.error(e);
				throw e;			
			} catch (MalformedQueryFault e) {
				logger.error(e);
				throw e;			
			} catch (InvalidIdFault e) {
				logger.error(e);
				throw e;
			} catch (InvalidFieldFault e) {
				logger.error(e);
				throw e;				
			} catch (UnexpectedErrorFault e) {
				logger.error(e);			
			} catch (InvalidQueryLocatorFault e) {
				logger.error(e);
			} catch (RemoteException e) {
				logger.error(e);		
			} catch (Exception e) {
				logger.error(e);	
			}
		}
		return null;
	}


	public List<SObject> getObjectsByMapDoubleSalesforce(String strSOQLStmt,Map<String, Integer> mapForeignIds) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		Integer querySize = 500;
		return this.getObjectsByMapDoubleSalesforce(strSOQLStmt,querySize,mapForeignIds,null);
	}   	
   	
	public List<SObject> getObjectsByMapSalesforce(String strSOQLStmt,Map<String, Integer> mapForeignIds) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		return this.getObjectsByMapSalesforce(strSOQLStmt,null,mapForeignIds);
	}
	
	public List<SObject> getObjectsByMapSalesforce(String strSOQLStmt,Map<String, Integer> mapForeignIds,String orderBy) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		return this.getObjectsByMapSalesforce(strSOQLStmt,null,mapForeignIds,orderBy);
	}	
	
	public List<SObject> getObjectsByMapSalesforce(String strSOQLStmt,Integer queryBatchSize,Map<String, Integer> mapForeignIds) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		return this.getObjectsByMapSalesforce(strSOQLStmt,queryBatchSize,mapForeignIds,null);
	}
	
	public List<SObject> getObjectsByMapDoubleSalesforce(String strSOQLStmt,Integer queryBatchSize,Map<String, Integer> mapForeignIds,String orderBy) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {		
		int numIntentos=0;		
		while (numIntentos++<MAX_INTENTOS) {
			try {
				return client.getObjectsByMapDoubleSalesforce(strSOQLStmt, queryBatchSize,mapForeignIds,orderBy);				
			} catch (LoginFault e) {
				logger.error(e);
				throw e;							
			} catch (InvalidSObjectFault e) {
				logger.error(e);
				throw e;			
			} catch (MalformedQueryFault e) {
				logger.error(e);
				throw e;			
			} catch (InvalidIdFault e) {
				logger.error(e);
				throw e;
			} catch (InvalidFieldFault e) {
				logger.error(e);
				throw e;				
			} catch (UnexpectedErrorFault e) {
				logger.error(e);			
			} catch (InvalidQueryLocatorFault e) {
				logger.error(e);
			} catch (RemoteException e) {
				logger.error(e);		
			} catch (Exception e) {
				logger.error(e);	
			}
		}
		return null;
	}
	
	
	public List<SObject> getObjectsByMapSalesforce(String strSOQLStmt,Integer queryBatchSize,Map<String, Integer> mapForeignIds,String orderBy) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {		
		int numIntentos=0;		
		while (numIntentos++<MAX_INTENTOS) {
			try {
				return client.getObjectsByMapSalesforce(strSOQLStmt, queryBatchSize,mapForeignIds,orderBy);				
			} catch (LoginFault e) {
				logger.error(e);
				throw e;							
			} catch (InvalidSObjectFault e) {
				logger.error(e);
				throw e;			
			} catch (MalformedQueryFault e) {
				logger.error(e);
				throw e;			
			} catch (InvalidIdFault e) {
				logger.error(e);
				throw e;
			} catch (InvalidFieldFault e) {
				logger.error(e);
				throw e;				
			} catch (UnexpectedErrorFault e) {
				logger.error(e);			
			} catch (InvalidQueryLocatorFault e) {
				logger.error(e);
			} catch (RemoteException e) {
				logger.error(e);		
			} catch (Exception e) {
				logger.error(e);	
			}
		}
		return null;
	}
	
   	public int getCountSalesforce(String strSOQLStmt) throws RemoteException,LoginFault,InvalidSObjectFault,MalformedQueryFault,InvalidIdFault,InvalidFieldFault,UnexpectedErrorFault,InvalidQueryLocatorFault,Exception {
		int numIntentos=0;		
		while (numIntentos++<MAX_INTENTOS) {
			try {
				return client.getCountSalesforce(strSOQLStmt);				
			} catch (LoginFault e) {
				logger.error(e);
				throw e;							
			} catch (InvalidSObjectFault e) {
				logger.error(e);
				throw e;			
			} catch (MalformedQueryFault e) {
				logger.error(e);
				throw e;			
			} catch (InvalidIdFault e) {
				logger.error(e);
				throw e;
			} catch (InvalidFieldFault e) {
				logger.error(e);
				throw e;				
			} catch (UnexpectedErrorFault e) {
				logger.error(e);			
			} catch (InvalidQueryLocatorFault e) {
				logger.error(e);
			} catch (RemoteException e) {
				logger.error(e);		
			} catch (Exception e) {
				logger.error(e);	
			}
		}
		return 0;
	}

	
	
	
	
	
	
	
	
	
	/*****************************************************************************************/
	/******************************FUNCIONES ESPECIFICAS**************************************/
	/*****************************************************************************************/
	/*****************************************************************************************/
	
	public Empresa obtenerConfiguracionEmpresa(String codigo) throws Exception {
		try {			
			String sql = 
						"Select " +
							"c.Name, c.Id,c.Metodo_Pago__c,Carga_Diaria_Maxima__c " + 
						"From Conf_Empresa__c c	" +  
						"Where  " +
							"c.Name = '" + codigo + "'";
				
				
			SObject object = this.getObjectSalesforce(sql);
							
			if (object!=null) {
				Conf_Empresa__c empresaObj = (Conf_Empresa__c) object;
				Empresa empresa = new Empresa();
				empresa.setName(empresaObj.getName());
				empresa.setMetodoPago(empresaObj.getMetodo_Pago__c());
				empresa.setCargaMaximaDiariaAgente(!Double.isNaN(empresaObj.getCarga_Diaria_Maxima__c())?(int)empresaObj.getCarga_Diaria_Maxima__c():0);
				empresa.setId(empresaObj.getId());

				//Trae la cartera, productos y moras de la empresa
				sql = "Select c.Name, c.Id, " +
						"(Select Id, Name, Cobro__c, Info_cuenta__c " +
							"From Configuraciones_info_productos__r), " +
						"(Select Id, Name, Dias_Desde__c, Dias_Hasta__c, " +
						"Marcador_Predictivo__c,Rebalse__c,Llamada__c,IsLegal__c,Mantener_Gestor__c From Configuraciones_info_mora__r order by Dias_Desde__c) " +
						"From Conf_Cartera__c c Where Empresa__c = '"+ empresa.getId()  + "'";
						
				List<SObject> objects = this.getObjectsSalesforce(sql);
				if (objects!=null) {
				for (SObject object1:objects) {					
						Conf_Cartera__c carteraObj = (Conf_Cartera__c) object1;
						Cartera cartera = new Cartera(carteraObj.getId(),carteraObj.getName());
						//Agrega los productos	
						
						List<SObject> objectsTemp1 = client.getObjectsSalesforce(carteraObj.getConfiguraciones_info_productos__r());
									
						for (SObject objectTemp:objectsTemp1) {
							Conf_Info_Producto__c productoObj = (Conf_Info_Producto__c) objectTemp;
							Producto producto = new Producto();
							producto.setId(productoObj.getId());
							producto.setNombre(productoObj.getName());
							producto.setRecordTypeInfoCuenta( UtilBasic.obtenerId(productoObj.getInfo_cuenta__c()));							
							producto.setRecordTypeCobro(UtilBasic.obtenerId(productoObj.getCobro__c()));							
							
							cartera.getProductos().add(producto);						
						}
						//Agrega las moras
						
						List<SObject> objectsTemp2 = client.getObjectsSalesforce(carteraObj.getConfiguraciones_info_mora__r());
						
						for (SObject objectTemp2:objectsTemp2) {
							Conf_Info_Mora__c moraObj = (Conf_Info_Mora__c) objectTemp2;							
							Mora mora = new Mora();
							mora.setId(moraObj.getId());
							mora.setDiasDesde(((Double)moraObj.getDias_Desde__c()).intValue());
							mora.setDiasHasta(((Double)moraObj.getDias_Hasta__c()).intValue());
							mora.setMarcadorPredictivo(moraObj.getMarcador_Predictivo__c());
							mora.setNombre(moraObj.getName());
							mora.setRebalse(moraObj.getRebalse__c());
							mora.setRecordTypeLlamada(UtilBasic.obtenerId(moraObj.getLlamada__c()));
							mora.setLegal(moraObj.getIsLegal__c());
							mora.setMantenerAgente(moraObj.getMantener_Gestor__c());
							
							if (mora.isMarcadorPredictivo()) {
								sql = "Select Maximo_Gestores_Diarias__c, Cola__c, Supervisor__c From Conf_Equipo_Agentes_Det__c Where Conf_Info_Mora__c = '" + moraObj.getId() + "' Limit 1";
								SObject object2 = this.getObjectSalesforce(sql);
								
								if (object2!=null) {
									Conf_Equipo_Agentes_Det__c colaObj = (Conf_Equipo_Agentes_Det__c) object2;							
									EquipoGestores equipo = new EquipoGestores();
									equipo.setCola(UtilBasic.obtenerId(colaObj.getCola__c()));
									equipo.setMaximoGestionesXDia(((Double)colaObj.getMaximo_Gestores_Diarias__c()).intValue());
									equipo.setSupervisor(colaObj.getSupervisor__c());									
									mora.setEquipoGestores(equipo);							
								}
							}
							
							cartera.getMoras().add(mora);
						}
						empresa.getCarteras().add(cartera);
					}					
				}
				
				return empresa;
			} else {
				return null;
			}			
		} catch (Exception e) {
			logger.error(e);
			throw e;
		}
	}		

}
